from soaplib.wsgi_soap import SimpleWSGISoapApp
from soaplib.service import soapmethod
from soaplib.serializers.primitive import Array, String, Integer

import hashlib
import datetime

from sqlalchemy.orm.exc import NoResultFound
from elixir import session

from data.models import *
from soap_types import *
from soap_mappers import *

class PyBooklerService(SimpleWSGISoapApp):

    def onResults(self,environ,py_results,soap_results):
        session.remove()

    def onReturn(self,environ,returnString):
        print "env: %s, return: %s" % (environ,returnString)
    
    @soapmethod(String, String, _returns=UserSoap)
    def user_login(self, user, passwd):
        """
        This soap method checks user and password in database.
        
        return: UserSoap instance; if no user is found id is set to -1
        """
        result = UserSoap()
        try:
            us = User.query.filter_by(username=user, password=passwd).one()
            result = map_user(us)
        except NoResultFound:
            result.id = -1
            
        return result
    
    @soapmethod(_returns=Array(UserSoap))
    def get_users(self):
        """
        This soap method retrieves all user in database.
        
        return: Array of UserSoap;
        """
        result = []
        
        users = User.query.filter(User.id>1).all()
        result = [map_user(user) for user in users]
           
        return result
    
    @soapmethod(_returns=Array(AuthorSoap))
    def get_authors(self):
        """
        This soap method retrieves all author in database.
        
        return: Array of AuthorSoap;
        """
        result = []
        
        authors = Author.query.all()
        result = [map_author(author) for author in authors]
            
        return result
    
    @soapmethod(_returns=Array(BookSoap))
    def get_books(self):
        """
        This soap method retrieves all book in database.
        
        return: Array of BookSoap;
        """
        result = []
        
        books = Book.query.all()
        result = [map_book(book) for book in books]
            
        return result
    
    @soapmethod(_returns=Array(BookshopSoap))
    def get_bookshops(self):
        """
        This soap method retrieves all bookshoap in database.
        
        return: Array of BookshopSoap;
        """
        result = []
        
        bookshops = Bookshop.query.all()
        result = [map_bookshop(bookshop) for bookshop in bookshops]
        
        return result
    
    @soapmethod(_returns=Array(ProductSoap))
    def get_products(self):
        """
        This soap method retrieves all product in database.
        
        return: Array of ProductSoap;
        """
        result = []
        
        products = Product.query.all()
        result = [map_product(product) for product in products]
        
        return result
    
    @soapmethod(_returns=Array(OrderSoap))
    def get_orders(self):
        """
        This soap method retrieves all product in database.
        
        return: Array of OrderSoap;
        """
        result = []
        
        orders = Order.query.all()
        result = [map_order(order) for order in orders]
        
        return result
    
    @soapmethod(_returns=Array(GenreSoap))
    def get_genres(self):
        """
        This soap method retrieves all product in database.
        
        return: Array of OrderSoap;
        """
        result = []
        
        genres = Genre.query.all()
        result = [map_genre(genre) for genre in genres]
        
        return result
    
    @soapmethod(AuthorSoap, _returns=Integer)
    def save_author(self, author):
        if not author:
            return -1
        
        if not author.id:
            authordb = Author()
        else:
            authordb = Author.get_by(id=author.id)
        
        authordb.name = author.name
        authordb.surname = author.surname
        
        session.commit()
        
        return authordb.id
    
    @soapmethod(AddressSoap, _returns=Integer)
    def save_address(self, address):
        if not address:
            return -1
        if not address.id:
            addressdb = Address()
        else:
            addressdb = Address.get_by(id=address.id)
        
        addressdb.address = address.address
        addressdb.postalcode = address.postalcode
        addressdb.city = address.city
        addressdb.province = address.province
        addressdb.country = address.country
        addressdb.type = address.type
        addressdb.subject = address.subject.id
        
        session.commit()
        
        return addressdb.id
    
    @soapmethod(BookSoap, _returns=Integer)
    def save_book(self, book):
        if not book:
            return -1
        if not book.id:
            bookdb = Book()
        else:
            bookdb = Book.get_by(id=book.id)
            
        bookdb.title = book.title
        bookdb.description = book.description
        for author in book.authors:
            au = Author.get_by(id=author)
            if au not in bookdb.authors:
                bookdb.authors.append(au)
        
        for genre in book.genres:
            ge = Genre.get_by(id=genre)
            if ge not in bookdb.genres:
                bookdb.genres.append(ge)
        
        for product in book.products:
            pr = Product.get_by(id=product)
            if pr not in bookdb.products:
                bookdb.products.append(pr)
                
        session.commit()
        
        return bokkdb.id
    
    @soapmethod(BookshopSoap, _returns=Integer)
    def save_bookshop(self, bookshop):
        if not bookshop:
            return -1
        if not bookshop.id:
            bookshopdb = Bookshop()
        else:
            bookshopdb = Bookshop.get_by(id=bookshop.id)
        
        bookshopdb.company_name = book.company_name
        bookshopdb.vat = bookshop.vat
        bookshopdb.iban = bookshop.iban
        for address in book.addresses:
            ad = Address.get_by(id=address)
            if ad not in bookshopdb.adresses:
                bookshopdb.adresses.append(ad)
                
        session.commit()
        
        return bookshopdb.id
    
    @soapmethod(ProductSoap, _returns=Integer)
    def save_product(self, product):
        if not product:
            return -1
        if not product.id:
            productdb = Product()
        else:
            productdb = product.get_by(id=product.id)
        
        productdb.name = product.name
        productdb.description = product.description
        productdb.edition = product.edition
        productdb.price = product.price
        productdb.quantity = product.quantity
        productdb.discount = product.discount
        for book in product.books:
            pr = Book.get_by(id=book)
            if pr not in productdb.books:
                productdb.books.append(pr)
        
        session.commit()
        
        return productdb.id
    
    @soapmethod(UserSoap, _returns=Integer)
    def save_user(self, user):
        if not user:
            return -1
        
        # query the subject before creating the user db object
        # to avoid autoflush problems
        subject = Subject.get_by(id=user.subject)
        
        if not user.id:
            userdb = User()
        else:
            userdb = User.get_by(id=user.id)
            
        userdb.username = user.username
        if user.password: 
            userdb.password = user.password
        userdb.active = user.active
        userdb.email = user.email
        userdb.subject = subject
        userdb.last_modify_date = datetime.datetime.now()
        
        session.commit()
        
        return userdb.id

    @soapmethod(OrderSoap, _returns=Integer)
    def save_order(self, order):
        if not order:
            return -1
        if not order.id:
            orderdb = Order()
        else:
            orderdb = Order.get_by(id=order.id)
        
        orderdb.bookshop = order.bookshop
        orderdb.date = order.date
        orderdb.status = order.status
        orderdb.total_amount = order.total_amount
        for detail in order.details:
            de = OrderDetail.get_by(order=order.detail)
            if de not in orderdb.details:
                orderdb.details.append(de)
        
        session.commit()
        
        return orderdb.id
    
    @soapmethod(GenreSoap)
    def save_genere(self, genre):
        if not genre:
            return -1
        
        try:
            Genre.get_by(name=genre.name)
            return -1
        except NoResultFound:
            pass
        
        if not genre.id:
            genredb = Genre()
        else:
            genredb = Genre.get_by(id=genre.id)
        
        genredb.name = genre.name
        genredb.description = genre.description
        
        session.commit()
        
        return genredb.id
    
    @soapmethod(AuthorSoap)
    def delete_author(self, author):
        authordb = Author.get_by(id=author.id)
        authordb.delete()
            
        session.commit()

    @soapmethod(BookSoap)
    def delete_book(self, book):
        bookdb = Book.get_by(id=book.id)
        bookdb.delete()
            
        session.commit()
    
    @soapmethod(BookshopSoap)
    def delete_bookshop(self, bookshop):
        bookshopdb = Bookshop.get_by(id=bookshop.id)
        bookshopdb.delete()
            
        session.commit()
    
    @soapmethod(ProductSoap)
    def delete_product(self, product):
        productdb = Product.get_by(id=product.id)
        productdb.delete()
            
        session.commit()
    
    @soapmethod(OrderSoap)
    def delete_order(self, order):
        orderdb = Order.get_by(id=order.id)
        orderdb.delete()
            
        session.commit()
    
    @soapmethod(UserSoap)
    def delete_user(self, user):
        userdb = User.get_by(id=user.id)
        userdb.delete()
            
        session.commit()
